﻿/*
    Copyright 2008 Travis Scholtens
    
    This file is part of Anticipa-Do List.

    Anticipa-Do List is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Anticipa-Do List is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Anticipa-Do List.  If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Xml;
using System.Xml.Linq;

namespace Anticipa_Do_List
{
    /// <summary>
    /// Interaction logic for TaskListWindow.xaml
    /// </summary>
    partial class TaskListWindow : Window
    {
        public TaskListWindow()
        {
            InitializeComponent();

            // build notifier list from available plugins
            foreach(string dll in Directory.GetFiles(Directory.GetCurrentDirectory(), "*.dll"))
                try
                {
                    var assembly = Assembly.LoadFile(dll);
                    foreach (Type type in assembly.GetTypes())
                        if (type.GetInterface(typeof(INotificationManager).Name) != null)
                            notifiers.Add(new Notifier(
                                    (INotificationManager)assembly.CreateInstance(type.FullName)));
                }
                catch { }

            // make sure that all enabled notifiers are fully defined; if so then set variables
            var configs = LoadConfig(notifiers);
            foreach(var notifier in notifiers)
                if (notifier.Enabled)
                {
                    var values = new List<string>();
                    foreach (var kv in notifier.NotificationManager.GetConfigurationKeys())
                        if (!configs[notifier.Type].ContainsKey(kv.Key))
                        {
                            notifier.Enabled = false;
                            break;
                        }
                        else
                            values.Add(configs[notifier.Type][kv.Key]);
                    if (notifier.Enabled)
                        notifier.NotificationManager.SetConfigurationValues(values);
                }

            taskList = LoadTasks();
            DataContext = taskList;
        }

        private ObservableCollection<Task> taskList;

        private List<Notifier> notifiers = new List<Notifier>();

        private void taskList_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            ListBox box = sender as ListBox;
            if (box != null)
            {
                Task task = box.SelectedItem as Task;
                if (task != null)
                {
                    NewEventWindow ev = new NewEventWindow(task.Name);
                    if (ev.ShowDialog().Value)
                        task.AddEvent(ev.Event);
                }
            }
        }

        private void new_Click(object sender, RoutedEventArgs e)
        {
            NewTaskWindow w = new NewTaskWindow();
            if (w.ShowDialog().Value)
                taskList.Add(w.Task);
        }

        private void config_Click(object sender, RoutedEventArgs e)
        {
            var config = LoadConfig(notifiers);
            new NotifierListWindow(notifiers, config).ShowDialog();
            SaveConfig(config, notifiers);
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            // establish notifications
            foreach(var notifier in notifiers)
                if(notifier.Enabled)
                    foreach (Task task in taskList)
                    {
                        DateTime? time = task.NextTime;
                        if (time != null)
                            notifier.NotificationManager.SetNotification(task.ID, task.Name, time.Value);
                    }

            // save tasks
            SaveTasks(taskList);
        }

        private const string CONFIG_FILE = "config.xml";

        private static void SaveConfig(Dictionary<string, Dictionary<string, string>> configs, List<Notifier> notifiers)
        {
            var enabled = new List<string>();
            foreach (var notifier in notifiers)
                if (notifier.Enabled)
                    enabled.Add(notifier.Type);

            XDocument doc = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XElement("config",
                    from type in configs.Keys
                    select new XElement("notifier",
                        new XAttribute("type", type),
                        new XAttribute("enabled", enabled.Contains(type)),
                        from variable in configs[type]
                        select new XElement("variable",
                            new XAttribute("key", variable.Key),
                            variable.Value))));
            doc.Save(CONFIG_FILE);
        }

        private static Dictionary<string, Dictionary<string, string>> LoadConfig(List<Notifier> notifiers)
        {
            var configs = new Dictionary<string, Dictionary<string, string>>();
            if (File.Exists(CONFIG_FILE))
            {
                XElement root = null;
                try
                {
                    root = XDocument.Load(CONFIG_FILE).Root;
                }
                catch { }
                if (root != null)
                    foreach (XElement t in root.Elements("notifier"))
                    {
                        var variables = new Dictionary<string, string>();
                        foreach (XElement v in t.Elements("variable"))
                            variables.Add(v.Attribute("key").Value, v.Value);

                        string type = t.Attribute("type").Value;
                        configs.Add(type, variables);

                        var enabled = t.Attribute("enabled");
                        if (enabled != null)
                            foreach (var notifier in notifiers)
                                if (notifier.Type == type)
                                    notifier.Enabled = bool.Parse(enabled.Value);
                    }
            }
            return configs;
        }

        private const string TASKS_FILE = "tasks.xml";

        private static void SaveTasks(ObservableCollection<Task> tasks)
        {
            XDocument doc = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XElement("tasks",
                    from task in tasks
                    select new XElement("task",
                        new XAttribute("name", task.Name),
                        new XAttribute("id", task.ID.ToString()),
                        from e in task.Events
                        select new object[] {
                            new XElement("event",
                                new XAttribute("type", e.Type.ToString()),
                                e.Time.ToString())
                        }
                    )
                )
            );
            doc.Save(TASKS_FILE);
        }

        private static ObservableCollection<Task> LoadTasks()
        {
            var tasks = new ObservableCollection<Task>();
            if (File.Exists(TASKS_FILE))
            {
                XElement root = null;
                try
                {
                    root = XDocument.Load(TASKS_FILE).Root;
                }
                catch { }
                if (root != null)
                    foreach (XElement t in root.Elements("task"))
                    {
                        Task task = new Task(t.Attribute("name").Value, new Guid(t.Attribute("id").Value));
                        foreach (XElement e in t.Elements("event"))
                        {
                            EventType type = (EventType)Enum.Parse(typeof(EventType), e.Attribute("type").Value);
                            DateTime time = DateTime.Parse(e.Value);
                            task.AddEvent(new Event(time, type));
                        }
                        tasks.Add(task);
                    }
            }
            return tasks;
        }
    }
}
